#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2019-08-15 12:37
# @Author  : yuxuecheng
# @Contact : yuxuecheng@xinluomed.com
# @Site    : 
# @File    : deep_auto_encoder.py
# @Software: PyCharm
# @Description 深度自编码器

from keras.layers import Input, Dense
from keras.models import Model
from keras import activations, optimizers, losses
from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt


# this is the size of our encoded representations
# 32 floats -> compression of factor 24.5, assuming the input is 784 floats
encoding_dim = 128

# this is our input placeholder
input_img = Input(shape=(784, ))

# "encoded" is the encoded representation of the input, use a stack of layers
encoded = Dense(128, activation=activations.relu)(input_img)
encoded = Dense(64, activation=activations.relu)(encoded)
encoded = Dense(32, activation=activations.relu)(encoded)

# "decoded" is the lossy reconstruction of the input
decoded = Dense(64, activation=activations.relu)(encoded)
encoded = Dense(128, activation=activations.relu)(decoded)
encoded = Dense(784, activation=activations.sigmoid)(encoded)

# this model maps an input to its reconstruction
auto_encoder = Model(input_img, decoded)

# this model maps an input to its encoded representation
encoder = Model(input_img, encoded)

# create a placeholder for an encoded (32-dimensional) input
encoded_input = Input(shape=(encoding_dim, ))

# retrieve the last layer of the auto_encoder model
decoded_layer = auto_encoder.layers[-1]

# create the decoder model
decoder = Model(encoded_input, decoded_layer(encoded_input))

# configure our model to use a per-pixel binary cross entropy loss, and the Ada delta optimizer
auto_encoder.compile(optimizer=optimizers.adadelta(), loss=losses.binary_crossentropy)

# prepare the input data
(x_train, _), (x_test, _) = mnist.load_data()

# normalize all values between 0 and 1 and we will flatten the 28x28 images into vectors of size 784.
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
print(x_train.shape)
print(x_test.shape)

auto_encoder.fit(x_train, x_train,
                 epochs=100,
                 batch_size=256,
                 shuffle=True,
                 validation_data=(x_test, x_test))

# encode and decode some digits
# note that we take them from the *test* set
encoded_imgs = encoder.predict(x_test)
decoded_imgs = decoder.predict(encoded_imgs)

# how many digits we will display
n = 10
plt.figure(figsize=(20, 4))
for i in range(n):
    # display original
    ax = plt.subplot(2, n, i + 1)
    plt.imshow(x_test[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # display reconstruction
    ax = plt.subplot(2, n, i + 1 + n)
    plt.imshow(decoded_imgs[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

plt.show()
plt.savefig('deep_auto_encoder.jpg')
